package com.ms.util;

/**
 * Created by RAZANERO on 31/01/14.
 */

import org.apache.commons.io.FileDeleteStrategy;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class FileUtil {
    private final static Logger LOG = Logger.getLogger(FileUtil.class);

    public static void forceDelete(File file) {
        if (file == null) return;
        try {
//            FileUtils.forceDelete(file);
            FileDeleteStrategy.FORCE.delete(file);
        } catch (IOException e) {
            LOG.error("Error al eliminar el archivo " + file.getAbsolutePath(), e);
        }

    }

    public static void writeToFile(File file, byte[] bytes) throws Exception {
        if (bytes == null) return;
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(bytes);
        fos.close();
    }

    public static File writeToFile(String sufix, byte[] bytes) throws Exception {
        File result = FileUtil.createTempFile(sufix);
        FileOutputStream fos = new FileOutputStream(result);
        fos.write(bytes);
        fos.close();
        return result;
    }


    public static File createTempFile(String suffix) throws IOException {
        String dir = System.getProperty("java.io.tmpdir");
        File file = File.createTempFile("dpworld_", suffix, new File(dir));
        return file;
    }

    public static String getFileName(String fileFullName) throws Exception {
        int indexStart1 = fileFullName.lastIndexOf("/");
        int indexStart2 = fileFullName.lastIndexOf("\\");
        int indexStart = Math.max(indexStart1, indexStart2);
        String fileName = fileFullName.substring(indexStart + 1);
        indexStart = fileName.lastIndexOf(".");
        fileName = fileName.substring(0, indexStart);
        return fileName;
    }

    public static String getFileExt(String fileFullName) {
        int indexStart1 = fileFullName.lastIndexOf("/");
        int indexStart2 = fileFullName.lastIndexOf("\\");

        int indexStart = Math.max(indexStart1, indexStart2);
        String fileName = fileFullName.substring(indexStart + 1);
        indexStart = fileName.lastIndexOf(".");
        if (indexStart == -1) return null;
        fileName = fileName.substring(indexStart, fileName.length());
        return fileName;
    }


    public static byte[] toByte(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            int c = 0;
            while ((c = fis.read()) != -1) {
                baos.write(c);
            }
            byte[] byteReturn = baos.toByteArray();
            return byteReturn;
        } finally {
            fis.close();
            baos.close();
        }
    }

    public static File fromBytes(File file, byte[] bytes) throws IOException {
        FileOutputStream fis = new FileOutputStream(file);
        try {
            fis.write(bytes);
            return file;
        } finally {
            fis.close();
        }
    }

    public static void makeWritable(File dir) {
        if (dir.exists()) {
            File[] ficheros = dir.listFiles();
            for (File fichero : ficheros) {
                makeReadableOthers(fichero);
                makeWritableOthers(fichero);
            }
        }
    }

    private static void makeWritableOthers(File fichero) {
        try {
            fichero.setWritable(true, false);
        } catch (SecurityException e) {
            Logger.getLogger(FileUtil.class).warn("No se pudo asignar permiso WRITABLE a " + fichero, e);
        }
    }

    private static void makeReadableOthers(File fichero) {
        try {
            fichero.setReadable(true, false);
        } catch (SecurityException e) {
            Logger.getLogger(FileUtil.class).warn("No se pudo asignar permiso READABLE a " + fichero, e);
        }
    }

    public static File copy(File in, File out) throws IOException {
        FileChannel inChannel = new FileInputStream(in).getChannel();
        FileChannel outChannel = new FileOutputStream(out).getChannel();
        try {
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } finally {
            if (inChannel != null) inChannel.close();
            if (outChannel != null) outChannel.close();
        }
        return out;
    }

    public static boolean nameContains(String fullPath, String extract) {
        return unix(fullPath).contains(unix(extract));
    }

    public static String unix(String fileName) {
        return fileName.replace('\\', '/');
    }

    public static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (String aChildren : children) {
                boolean success = deleteDir(new File(dir, aChildren));
                if (!success) {
                    return false;
                }
            }
        }

        // The directory is now empty so delete it
        return dir.delete();
    }

    public static String buildDir(String idEmisor, String tipoDocumento, String idDocumento, String carpetaBase) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String carpetaFecha = StringUtils.replace(sdf.format(new Date()), "-", File.separator);
        String carpetaDocumento = tipoDocumento + "-" + idDocumento;
        String carpeta = carpetaBase + File.separator + idEmisor + File.separator + carpetaFecha + File.separator + carpetaDocumento;
        File dir = new File(carpeta);
        if (dir.exists()) {
            if (!FileUtil.deleteDir(dir)) {
                throw new IllegalArgumentException("Error al borrar la carpeta " + carpeta);
            }
        }
        if (!dir.mkdirs()) {
            throw new IllegalArgumentException("Error al crear la carpeta " + carpeta);
        }
        return carpeta;
    }

    public static File crearSignatureFile(String directorio, String fileName) {
        File result = null;
        try {
            result = new File(directorio, fileName);
            if (!result.createNewFile()) {
                throw new IllegalArgumentException("Error al crear el archivo " + result.getAbsolutePath());
            }
        } catch (IOException e) {
            throw new IllegalArgumentException("Error al crear el archivo " + result.getAbsolutePath());
        }
        return result;
    }


    public static void outputDocToFile(Document doc, File file) throws Exception {
        FileOutputStream fos = new FileOutputStream(file);
        OutputStreamWriter out = new OutputStreamWriter(fos, Charset.forName("UTF-8"));

        TransformerFactory factory = TransformerFactory.newInstance("org.apache.xalan.processor.TransformerFactoryImpl", null);
        Transformer transformer = factory.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        transformer.setOutputProperty(OutputKeys.ENCODING, "WINDOWS-1252");
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
        transformer.setOutputProperty(OutputKeys.CDATA_SECTION_ELEMENTS, "" +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}Value " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}StreetName " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}CityName " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}CitySubdivisionName " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}Description " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}RegistrationName " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}CityName " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}CountrySubentity " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}District " +
                "{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}Name");
        transformer.transform(new DOMSource(doc), new StreamResult(out));

        out.close();
        fos.close();
    }

    public static void changeTagName(Document doc, String fromTag, String toTag) {
        NodeList nodes = doc.getElementsByTagName("ext:UBLExtension");

        Node currentNode = null;
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            Node nodeId = node.getChildNodes().item(0);
            if ("EBIZ".equals(nodeId.getTextContent())) {
                currentNode = node;
            }
        }
        if (currentNode == null) return;
        Node extensionContent = currentNode.getLastChild();
        Node additionalInformation = extensionContent.getFirstChild();
        NodeList nodeList = ((Element) additionalInformation).getElementsByTagName("sac:AdditionalProperty");
        List<Node> nuevo = new ArrayList<Node>();
        for (int i = 0; i < nodeList.getLength(); i++) {
            nuevo.add(nodeList.item(i));
        }
        Element cbcAdditionalInformation = doc.createElement("cbc:AdditionalInformation");
        for (Iterator<Node> iterator = nuevo.iterator(); iterator.hasNext(); ) {
            Node node = iterator.next();
            cbcAdditionalInformation.appendChild(node);
        }

        extensionContent.appendChild(cbcAdditionalInformation);
        extensionContent.removeChild(additionalInformation);

    }

    static final int BUFFER = 2048;

    public static final String FILE_NAME_DEFAULT = "dpworld";

    static public String convertToString(File aFile) {
        StringBuffer str = new StringBuffer();
        try {
            BufferedReader input = new BufferedReader(new FileReader(aFile));
            try {
                String linea = null;
                while ((linea = input.readLine()) != null) {
                    if (StringUtils.isNotBlank(linea))
                        str.append(linea.trim());
                }
            } finally {
                input.close();
            }
        } catch (IOException ex) {
            throw new RuntimeException();
        }
        return str.toString();
    }

    public static File extractFileFromZip(String prefix, File fileResponse) {
        try {
            BufferedOutputStream dest = null;
            FileInputStream fis = new
                    FileInputStream(fileResponse);
            ZipInputStream zis = new
                    ZipInputStream(new BufferedInputStream(fis));
            ZipEntry entry;
            File result = createTempFile(prefix);
            while ((entry = zis.getNextEntry()) != null) {
                int count;
                byte data[] = new byte[BUFFER];

                if (!(entry.getName().endsWith(prefix) || entry.getName().startsWith(prefix))) continue;

                FileOutputStream fos = new
                        FileOutputStream(result);
                dest = new
                        BufferedOutputStream(fos, BUFFER);
                while ((count = zis.read(data, 0, BUFFER)) != -1) {
                    dest.write(data, 0, count);
                }
                dest.flush();
                dest.close();
            }
            zis.close();
            fis.close();
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Error al extraer del zip", e);
        }
    }

    public static void main(String[] args) {
        System.out.println(System.getProperty("java.io.tmpdir"));
    }

}
